-- volcano_api.lua - 火山引擎API访问库
-- 功能：提供对火山引擎API的封装访问

-- 导入webclient库
local webclient = require("lib_web_client")
-- 导入cjson库用于JSON解析
local cjson = require("cjson")
-- 导入fs模块用于文件操作
local fs = require("fs")
-- 导入volvano_func模块
local volvano_func = require("volvano_func")

-- 默认配置参数
local VOLCANO_API_HOST = "ark.cn-beijing.volces.com"
local VOLCANO_API_PORT = 443
local CA_CERT_PATH = "/fs/web/cacert-2025-07-15.pem"
local API_PATH = "/api/v3/chat/completions"

-- 默认最大上下文消息数
local DEFAULT_MAX_CONTEXT_MESSAGES = 20  -- 默认保留20条消息（10轮对话）

-- 日志函数


-- 辅助函数：处理字符串中的特殊字符，确保可以安全地用于JSON
local function sanitizeString(str)
    if not str or type(str) ~= "string" then
        return tostring(str or "")
    end
    
    -- 替换可能导致JSON解析问题的控制字符
    -- 注意：cjson.encode会自动处理引号和反斜杠等，但我们需要确保字符串是有效的
    local sanitized = str
        :gsub("\r", "\\r")  -- 替换回车符
        :gsub("\n", "\\n")  -- 替换换行符
        :gsub("\t", "\\t")  -- 替换制表符
        
    return sanitized
end

-- VolcanoApi类定义
-- self.config.thinking属性在实例创建时定义，默认值为"disabled"
local VolcanoApi = {}
VolcanoApi.__index = VolcanoApi

-- 全局函数注册表，所有实例共享
VolcanoApi.globalFunctions = {}

-- 创建函数
-- config参数作为函数输入参数传入，包含modelId、apiKey等配置信息
function VolcanoApi:create(config)
    -- 配置参数验证
    if not config then
        return nil, "Configuration table is required"
    end
    
    -- 参数验证
    if not config.modelId or config.modelId == "" then
        return nil, "modelId is required and cannot be empty"
    end
    
    if not config.apiKey or config.apiKey == "" then
        return nil, "apiKey is required and cannot be empty"
    end
    
    -- 默认参数
    local thinking_mode = config.thinking or "disabled"  -- 默认关闭思考模式
    local max_tokens = config.maxTokens or 1000    -- 默认最大长度1000
    local temperature = config.temperature or 0.7  -- 默认采样温度0.7
    local max_context_messages = config.maxContextLength or DEFAULT_MAX_CONTEXT_MESSAGES -- 默认上下文长度
    
    -- 验证thinking参数取值范围
    local valid_thinking_values = {enabled = true, disabled = true, auto = true}
    if not valid_thinking_values[thinking_mode] then
        return nil, "thinking must be one of: enabled, disabled, auto"
    end
    
    -- 验证temperature范围
    if temperature < 0 or temperature > 2 then
        return nil, "temperature must be between 0 and 2"
    end
    
    -- 读取rule文件内容（如果提供了ruleFilePath）
    local rule_content = nil
    if config.ruleFilePath and type(config.ruleFilePath) == "string" and config.ruleFilePath ~= "" then
        log_info("Reading rule file from: " .. config.ruleFilePath)
        -- 使用fs模块读取rule文件
        rule_content = fs.readFile(config.ruleFilePath)
        if rule_content then
            log_info("Rule file loaded successfully, length: " .. #rule_content)
        else
            log_error("Failed to open rule file: " .. config.ruleFilePath)
            -- 不返回错误，只记录日志，允许继续执行
        end
    end
    
    -- 尝试初始化全局工具函数（只在首次创建对象时执行）
    if not VolcanoApi.functionsInitialized then
        log_info("初始化火山引擎全局工具函数")
        -- 传入VolcanoApi类对象，避免循环引用
        local init_success, result = pcall(volvano_func.volvanoFuncInit, VolcanoApi)
        if not init_success or not result then
            log_error("全局工具函数初始化失败，但将继续创建API实例")
        else
            VolcanoApi.functionsInitialized = true
            log_info("全局工具函数初始化成功")
        end
    end
    
    -- 创建web客户端连接
    log_info("Creating web client connection to " .. VOLCANO_API_HOST .. ":" .. VOLCANO_API_PORT)
    local client, err = webclient.create(VOLCANO_API_HOST, VOLCANO_API_PORT, CA_CERT_PATH)
    
    if not client then
        log_error("Failed to create web client: " .. err)
        return nil, err
    end
    
    log_info("Web client created successfully")
    
    -- 创建实例
    local instance = {
        client = client,
        config = {
            modelId = config.modelId,
            apiKey = config.apiKey,
            thinking = thinking_mode,
            maxTokens = max_tokens,
            temperature = temperature,
            maxContextMessages = max_context_messages,
            ruleFilePath = config.ruleFilePath -- 保存rule文件路径
        },
        -- 对话历史存储
        conversationHistory = {},
        -- 系统提示存储（不会被截断的rule内容）
        systemPrompts = {},
        -- 已注册的函数存储
        registeredFunctions = {}
    }
    
    -- 如果成功读取了rule文件内容，将其添加到系统提示中
    if rule_content then
        table.insert(instance.systemPrompts, {role = "user", content = rule_content})
        log_info("Rule content added to system prompts")
    end
    
    setmetatable(instance, self)
    return instance
  end
  
  -- 注册函数（实例级）
  function VolcanoApi:registerFunction(func_name, func_desc, parameters, callback)
      if not func_name or type(func_name) ~= "string" or func_name == "" then
          return nil, "Function name must be a non-empty string"
      end
      
      if not func_desc or type(func_desc) ~= "string" then
          return nil, "Function description must be a string"
      end
      
      if not parameters or type(parameters) ~= "table" then
          return nil, "Parameters must be a table"
      end
      
      if not callback or type(callback) ~= "function" then
          return nil, "Callback must be a function"
      end
      
      self.registeredFunctions[func_name] = {
          callback = callback,
          description = func_desc,
          parameters = parameters
      }
      
      log_info("Function registered (instance): " .. func_name)
      return true
  end
  
  -- 注册全局函数（所有实例共享）
  function VolcanoApi.registerGlobalFunction(func_name, func_desc, parameters, callback)
      if not func_name or type(func_name) ~= "string" or func_name == "" then
          return nil, "Function name must be a non-empty string"
      end
      
      if not func_desc or type(func_desc) ~= "string" then
          return nil, "Function description must be a string"
      end
      
      if not parameters or type(parameters) ~= "table" then
          return nil, "Parameters must be a table"
      end
      
      if not callback or type(callback) ~= "function" then
          return nil, "Callback must be a function"
      end
      
      VolcanoApi.globalFunctions[func_name] = {
          callback = callback,
          description = func_desc,
          parameters = parameters
      }
      
      log_info("Global function registered: " .. func_name)
      return true
  end
  
  -- 移除已注册的函数（实例级）
  function VolcanoApi:unregisterFunction(func_name)
      if self.registeredFunctions[func_name] then
          self.registeredFunctions[func_name] = nil
          log_info("Function unregistered (instance): " .. func_name)
          return true
      end
      return false, "Function not found in instance"
  end
  
  -- 移除全局函数
  function VolcanoApi.unregisterGlobalFunction(func_name)
      if VolcanoApi.globalFunctions[func_name] then
          VolcanoApi.globalFunctions[func_name] = nil
          log_info("Global function unregistered: " .. func_name)
          return true
      end
      return false, "Global function not found"
  end
  
  -- 获取已注册的函数列表（实例级）
  function VolcanoApi:getRegisteredFunctions()
      return self.registeredFunctions
  end
  
  -- 获取全局函数列表
  function VolcanoApi.getGlobalFunctions()
      return VolcanoApi.globalFunctions
  end
  
  -- 获取所有可用函数（合并全局和实例级）
  function VolcanoApi:getAllAvailableFunctions()
      local all_functions = {}
      
      -- 先添加全局函数
      for name, info in pairs(VolcanoApi.globalFunctions) do
          all_functions[name] = info
      end
      
      -- 再添加实例级函数（实例级可以覆盖全局函数）
      for name, info in pairs(self.registeredFunctions) do
          all_functions[name] = info
      end
      
      return all_functions
  end
  
  -- 构建请求体

-- 构建请求体
function VolcanoApi:_buildRequestBody(messages)
    -- thinking_type直接使用配置中的值（enabled、disabled或auto）
    local thinking_type = self.config.thinking
    
    -- 合并系统提示和消息
    local all_messages = {}
    
    -- 首先添加系统提示（rule内容）
    if self.systemPrompts and #self.systemPrompts > 0 then
        for _, prompt in ipairs(self.systemPrompts) do
            table.insert(all_messages, prompt)
        end
    end
    
    -- 然后添加用户提供的消息
    if messages and #messages > 0 then
        for _, msg in ipairs(messages) do
            table.insert(all_messages, msg)
        end
    end
    
    -- 使用cjson库构建请求体，确保JSON格式正确
    local request_data = {
        messages = all_messages,
        model = self.config.modelId,
        stream_options = {include_usage = false},
        thinking = {type = thinking_type},
        max_tokens = self.config.maxTokens,
        temperature = self.config.temperature
    }
    
    -- 获取所有可用函数（全局+实例）
    local all_functions = self:getAllAvailableFunctions()
    
    if next(all_functions) then
        local tools = {}
        for func_name, func_info in pairs(all_functions) do
            table.insert(tools, {
                type = "function",
                ['function'] = {
                    name = func_name,
                    description = func_info.description,
                    parameters = func_info.parameters
                }
            })
        end
        request_data.tools = tools
        log_info("Added " .. #tools .. " available function(s) to request")
    end
    
    -- 使用cjson.encode生成正确的JSON字符串
    local request_body = cjson.encode(request_data)
    
    log_debug("Prepared request body (length: " .. #request_body .. ")")
    return request_body
end

-- 构建HTTP请求
function VolcanoApi:_buildHttpRequest(request_body)
    -- 确保request_body是一个有效的字符串
    if not request_body or type(request_body) ~= "string" then
        log_error("Invalid request body: must be a string")
        return nil
    end
    
    -- 构建HTTP请求，确保格式正确
    -- 注意：request_body已经通过cjson.encode正确转义了内部的引号和特殊字符
    -- 这里我们直接拼接，因为HTTP协议允许在请求体中包含这些已转义的字符
    local http_request = string.format(
        "POST %s HTTP/1.1\r\n" ..
        "Host: %s\r\n" ..
        "Content-Type: application/json\r\n" ..
        "Authorization: Bearer %s\r\n" ..
        "Content-Length: %d\r\n" ..
        "Connection: keep-alive\r\n" ..
        "\r\n%s",
        API_PATH, 
        VOLCANO_API_HOST, 
        self.config.apiKey, 
        #request_body,
        request_body
    )
    
    log_debug("HTTP Request (length: " .. #http_request .. ")")
    return http_request
end

-- 发送请求函数
function VolcanoApi:sendRequest(messages)
    if not messages or #messages == 0 then
        return nil, "Messages array is required"
    end
    
    -- 确保客户端连接存在
    if not self.client then
        log_error("No active web client connection")
        return nil, "No active web client connection"
    end
    
    -- 构建请求体和HTTP请求
    local request_body = self:_buildRequestBody(messages)
    local http_request = self:_buildHttpRequest(request_body)
    
    -- 发送HTTP请求
    log_info("Sending HTTP request...")
    local bytes_written, write_err = self.client:write(http_request)
    
    if not bytes_written then
        log_error("Failed to send HTTP request: " .. write_err)
        return nil, write_err
    end
    
    log_info("Sent HTTP request successfully, bytes: " .. bytes_written)
    return true
end

-- 读取响应函数（自动过滤HTTP头）
function VolcanoApi:readResponse()
    log_info("Waiting for response...")

    -- 确保客户端连接存在
    if not self.client then
        log_error("No active web client connection")
        return nil, "No active web client connection"
    end
    local rlen = self.config.maxTokens * 10
    if self.config.thinking == "enabled" then
        rlen = rlen * 2
    end
    -- 读取响应数据，直接调用client:read，client会处理好分包接收
    local data, bytes_read = self.client:read(rlen)
    
    if not data then
        log_error("Failed to read response: " .. bytes_read)
        return nil, bytes_read
    end
    
    log_info("Received " .. bytes_read .. " bytes")
    
    -- 尝试提取JSON响应体（自动过滤HTTP头）
    local json_body = data:match("\r\n\r\n(.*)")
    if json_body then
        log_info("Extracted JSON body (length: " .. #json_body .. ")")
        return json_body
    else
        -- 如果无法提取JSON体，直接返回原始数据
        log_info("Returning raw response data")
        return data
    end
end

-- 添加用户消息到对话历史
function VolcanoApi:addUserMessage(content)
    -- 使用sanitizeString函数处理消息内容，确保可以安全地用于JSON
    local sanitized_content = sanitizeString(content)
    table.insert(self.conversationHistory, {role = "user", content = sanitized_content})
    self:_truncateConversationHistory()
end

-- 添加助手回复到对话历史
function VolcanoApi:addAssistantMessage(content)
    -- 使用sanitizeString函数处理消息内容，确保可以安全地用于JSON
    local sanitized_content = sanitizeString(content)
    table.insert(self.conversationHistory, {role = "assistant", content = sanitized_content})
    self:_truncateConversationHistory()
end

-- 添加工具消息到对话历史
function VolcanoApi:addToolMessage(content, tool_call_id)
    -- 使用sanitizeString函数处理消息内容，确保可以安全地用于JSON
    local sanitized_content = sanitizeString(content)
    local tool_message = {
        role = "tool",
        content = sanitized_content
    }
    -- 如果提供了tool_call_id，则添加到消息中
    if tool_call_id then
        tool_message.tool_call_id = tool_call_id
    end
    table.insert(self.conversationHistory, tool_message)
    self:_truncateConversationHistory()
end

-- 获取对话历史
function VolcanoApi:getConversationHistory()
    -- 返回对话历史的副本，避免外部直接修改
    local history_copy = {}
    for i, msg in ipairs(self.conversationHistory) do
        -- 创建消息副本，包含所有必要字段
        local msg_copy = {role = msg.role, content = msg.content}
        -- 如果有tool_call_id字段，也复制它
        if msg.tool_call_id then
            msg_copy.tool_call_id = msg.tool_call_id
        end
        history_copy[i] = msg_copy
    end
    return history_copy
end

-- 清空对话历史
function VolcanoApi:clearConversationHistory()
    self.conversationHistory = {}
    log_info("Conversation history cleared")
end

-- 截断对话历史，保持在最大长度以内
function VolcanoApi:_truncateConversationHistory()
    local max_length = self.config.maxContextMessages
    if #self.conversationHistory > max_length then
        local overflow = #self.conversationHistory - max_length
        -- 从开头移除多余的消息
        for i = 1, overflow do
            table.remove(self.conversationHistory, 1)
        end
        log_info("Conversation history truncated, removed " .. overflow .. " message(s)")
    end
end

-- 聊天函数（发送消息并获取回复）
-- 支持两种使用方式：
-- 1. 传入完整的消息数组：chat(messages)
-- 2. 传入单个消息内容：chat(message_content)
function VolcanoApi:chat(messages)
    log_debug("[DEBUG] VolcanoApi:chat - 开始执行聊天函数")
    local messages_to_send
    
    -- 打印输入参数类型和内容
    if type(messages) == "string" then
        log_debug("[DEBUG] VolcanoApi:chat - 接收到字符串类型消息: " .. (messages or "空"))
        if messages and messages ~= "" then
            -- 如果传入的是非空字符串，则作为用户消息添加到对话历史
            self:addUserMessage(messages)
        end
        -- 无论是否添加新消息，都使用对话历史
        messages_to_send = self:getConversationHistory()
        log_debug("[DEBUG] VolcanoApi:chat - 使用对话历史，消息数量: " .. #messages_to_send)
    else
        log_debug("[DEBUG] VolcanoApi:chat - 接收到消息数组，消息数量: " .. (messages and #messages or 0))
        -- 如果传入的是消息数组，则直接使用
        messages_to_send = messages
    end
    
    -- 发送请求
    log_debug("[DEBUG] VolcanoApi:chat - 准备发送请求")
    local success, err = self:sendRequest(messages_to_send)
    if not success then
        log_debug("[DEBUG] VolcanoApi:chat - 发送请求失败: " .. (err or "未知错误"))
        return nil, err
    end
    log_debug("[DEBUG] VolcanoApi:chat - 发送请求成功")
    
    -- 读取响应
    log_debug("[DEBUG] VolcanoApi:chat - 准备读取响应")
    local response, resp_err = self:readResponse()
    log_debug("[DEBUG] VolcanoApi:chat - 读取响应完成，是否成功: " .. (response and "true" or "false"))
    
    if response and type(messages) == "string" then
        log_debug("[DEBUG] VolcanoApi:chat - 响应数据长度: " .. #response)
        log_debug("[DEBUG] VolcanoApi:chat - 开始解析JSON响应")
        -- 如果是使用对话历史模式，尝试解析AI回复并添加到历史记录
        -- 使用cjson库解析JSON响应，这比loadstring更安全、更高效
        local success, json_obj = pcall(cjson.decode, response)
        
        if not success then
            log_debug("[DEBUG] VolcanoApi:chat - JSON解析失败: " .. (tostring(json_obj) or "未知错误"))
        elseif not json_obj then
            log_debug("[DEBUG] VolcanoApi:chat - 解析结果为空")
        elseif not json_obj.choices then
            log_debug("[DEBUG] VolcanoApi:chat - JSON中没有choices字段")
        elseif not json_obj.choices[1] then
            log_debug("[DEBUG] VolcanoApi:chat - choices数组为空")
        elseif not json_obj.choices[1].message then
            log_debug("[DEBUG] VolcanoApi:chat - 缺少message字段")
        elseif not json_obj.choices[1].message.content or json_obj.choices[1].message.content == "" then
            log_debug("[DEBUG] VolcanoApi:chat - content字段为空")
            
            -- 检查是否有工具调用
            if json_obj.choices[1].message.tool_calls and #json_obj.choices[1].message.tool_calls > 0 then
                log_debug("[DEBUG] VolcanoApi:chat - 检测到工具调用")
                
                -- 处理工具调用并记录结果
                local tool_results = {}
                for _, tool_call in ipairs(json_obj.choices[1].message.tool_calls) do
                    -- 添加更健壮的nil检查，使用字符串形式访问function字段（避免关键字冲突）
                    if type(tool_call) == "table" and tool_call.type == "function" and tool_call["function"] then

                        local func_name = tool_call["function"].name
                        local func_args = tool_call["function"].arguments
                        
                        log_info("Received function call request: " .. func_name)
                        
                        -- 检查函数是否在实例中注册
                        local func_info = self.registeredFunctions[func_name]
                        local is_global = false
                        
                        -- 如果实例中没有，检查全局函数
                        if not func_info then
                            func_info = VolcanoApi.globalFunctions[func_name]
                            is_global = true
                        end
                        
                        if func_info then
                            log_debug("[DEBUG] VolcanoApi:chat - 找到" .. (is_global and "全局" or "实例") .. "函数: " .. func_name)
                            
                            -- 解析参数
                            local args_table = {}
                            if func_args and type(func_args) == "string" and func_args ~= "" then
                                local args_success, parsed_args = pcall(cjson.decode, func_args)
                                if args_success and parsed_args then
                                    args_table = parsed_args
                                else
                                    log_error("Failed to parse function arguments: " .. (tostring(parsed_args) or "unknown error"))
                                end
                            end
                            
                            -- 调用回调函数
                            local callback = func_info.callback
                            local call_success, result = pcall(callback, args_table)
                            if call_success then
                                log_info("Function call successful (" .. (is_global and "global" or "instance") .. "): " .. func_name)
                                -- 保存工具执行结果
                                table.insert(tool_results, {
                                    tool_call_id = tool_call.id,
                                    function_name = func_name,
                                    result = result,
                                    success = true
                                })
                            else
                                log_error("Function call failed: " .. (tostring(result) or "unknown error"))
                                -- 保存工具执行失败结果
                                table.insert(tool_results, {
                                    tool_call_id = tool_call.id,
                                    function_name = func_name,
                                    error = tostring(result),
                                    success = false
                                })
                            end
                        else
                            log_error("Function not registered: " .. func_name)
                            -- 保存未注册函数的错误结果
                            table.insert(tool_results, {
                                tool_call_id = tool_call.id,
                                function_name = func_name,
                                error = "Function not registered",
                                success = false
                            })
                        end
                    end
                end
                
                -- 如果有工具调用结果，将其添加到对话历史并继续对话
                if #tool_results > 0 then
                    log_debug("[DEBUG] VolcanoApi:chat - 工具调用完成，准备将结果添加到对话历史")
                    
                    -- 将AI的工具调用请求添加到历史记录
                    -- 将工具调用信息序列化为字符串用于记录
                    local tool_call_info = "AI调用工具: "
                    if json_obj.choices[1].message.tool_calls and #json_obj.choices[1].message.tool_calls > 0 then
                        local tool_names = {}
                        for _, tc in ipairs(json_obj.choices[1].message.tool_calls) do
                            if tc["function"] and tc["function"].name then
                                table.insert(tool_names, tc["function"].name)
                            end
                        end
                        tool_call_info = tool_call_info .. table.concat(tool_names, ", ")
                    end
                    self:addAssistantMessage(tool_call_info)
                    
                    -- 将工具执行结果添加到对话历史
                    for _, tool_result in ipairs(tool_results) do
                        local result_content
                        if tool_result.success then
                            -- 尝试将结果序列化为JSON格式，以便更好地在对话中展示
                            local result_str = tool_result.result
                            if type(tool_result.result) == "table" then
                                local success, json_result = pcall(cjson.encode, tool_result.result)
                                if success then
                                    result_str = json_result
                                else
                                    result_str = tostring(tool_result.result)
                                end
                            end
                            result_content = "工具调用结果: " .. tool_result.function_name .. ": " .. tostring(result_str)
                        else
                            result_content = "工具调用失败: " .. tool_result.function_name .. ": " .. tostring(tool_result.error)
                        end
                        -- 正确使用addToolMessage方法，传入字符串内容和tool_call_id
                        self:addToolMessage(result_content, tool_result.tool_call_id)
                    end
                    
                    -- 重新调用chat方法继续对话（传入空字符串表示使用更新后的对话历史）
                    log_debug("[DEBUG] VolcanoApi:chat - 重新调用chat方法继续对话")
                    return self:chat("")
                end
            end
        else
            log_debug("[DEBUG] VolcanoApi:chat - 成功解析响应内容")
            self:addAssistantMessage(json_obj.choices[1].message.content)
        end
    end
    
    -- 在函数执行完成时，删除对话历史中的所有工具调用相关记录（请求和结果），只保留用户问题和AI的最终回答
    -- 找出所有工具调用相关的消息索引（包括工具调用请求和工具调用结果）
    local indices_to_remove = {}
    local last_user_index = 0
    
    -- 首先找出最后一条用户消息的索引
    for i, msg in ipairs(self.conversationHistory) do
        if msg.role == 'user' then
            last_user_index = i
        end
    end
    
    -- 然后删除最后一条用户消息之后的所有工具调用相关记录，直到找到AI的最终回答
    local found_final_answer = false
    for i = #self.conversationHistory, last_user_index + 1, -1 do
        local msg = self.conversationHistory[i]
        -- 如果找到了AI的非工具调用回答，记录下来但不删除
        if msg.role == 'assistant' and msg.content and string.sub(msg.content, 1, 8) ~= 'AI调用工具:' then
            if not found_final_answer then
                found_final_answer = true
                -- 记录这个最终回答的位置，之后的记录都要删除
                for j = i-1, last_user_index + 1, -1 do
                    table.insert(indices_to_remove, j)
                end
                break
            end
        end
    end
    
    -- 如果没有找到AI的最终回答（可能是异常情况），则删除所有工具调用相关记录
    if not found_final_answer then
        for i, msg in ipairs(self.conversationHistory) do
            if (msg.role == 'assistant' and msg.content and string.sub(msg.content, 1, 8) == 'AI调用工具:') or 
               (msg.role == 'tool') then
                table.insert(indices_to_remove, i)
            end
        end
    end
    
    -- 对要删除的索引进行排序（从大到小），避免删除时索引错乱
    table.sort(indices_to_remove, function(a, b) return a > b end)
    
    -- 执行删除操作
    for _, idx in ipairs(indices_to_remove) do
        table.remove(self.conversationHistory, idx)
    end
    
    log_debug("[DEBUG] VolcanoApi:chat - 函数执行完成")
    return response, resp_err
end

-- 关闭连接
function VolcanoApi:close()
    if self.client then
        self.client:close()
        self.client = nil
        log_info("Web client connection closed")
    end
end

-- 模块导出
return {
    create = function(config)
        return VolcanoApi:create(config)
    end,
    -- 导出全局函数注册方法
    registerGlobalFunction = VolcanoApi.registerGlobalFunction,
    unregisterGlobalFunction = VolcanoApi.unregisterGlobalFunction,
    getGlobalFunctions = VolcanoApi.getGlobalFunctions
}